<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Image Gallery - Generation Data</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <style>
        /* Ensure the layout takes full height and prevents overflow */
        html, body {
            height: 100%;
            margin: 0;
            padding: 0;
            overflow: hidden;
        }
        
        /* Ensure image container uses flexbox properly */
        #image-area {
            min-height: 0; /* Allow flex child to shrink */
        }
        
        /* Make sure the image scales properly */
        #main-image {
            max-width: calc(100% - 2rem); /* Account for padding */
            max-height: calc(100% - 2rem); /* Account for padding */
        }
    </style>
    <script>
        let currentWorkflowData = null;

        function openInFileExplorer(path) {
            // For Windows file explorer
            if (navigator.platform.indexOf('Win') > -1) {
                // This will work in Electron apps or desktop environments
                try {
                    window.require('child_process').exec(`explorer /select,"${path}"`);
                } catch (e) {
                    // Fallback: copy path to clipboard and show alert
                    navigator.clipboard.writeText(path).then(() => {
                        alert('File path copied to clipboard: ' + path);
                    }).catch(() => {
                        alert('File path: ' + path);
                    });
                }
            } else {
                // For other platforms, just copy to clipboard
                navigator.clipboard.writeText(path).then(() => {
                    alert('File path copied to clipboard: ' + path);
                }).catch(() => {
                    alert('File path: ' + path);
                });
            }
        }

        async function copyToClipboard(text, button) {
            try {
                await navigator.clipboard.writeText(text);
                // Show temporary feedback
                const originalContent = button.innerHTML;
                button.innerHTML = '✓ Copied!';
                button.classList.add('text-green-400');
                setTimeout(() => {
                    button.innerHTML = originalContent;
                    button.classList.remove('text-green-400');
                }, 1000);
            } catch (err) {
                alert('Copy failed: ' + err);
            }
        }

        function copyPositivePrompt(event) {
            if (currentWorkflowData && currentWorkflowData.positivePrompt) {
                copyToClipboard(currentWorkflowData.positivePrompt, event.target.closest('button'));
            }
        }

        function copyNegativePrompt(event) {
            if (currentWorkflowData && currentWorkflowData.negativePrompt) {
                copyToClipboard(currentWorkflowData.negativePrompt, event.target.closest('button'));
            }
        }

        function downloadWorkflowJSON() {
            if (currentWorkflowData && currentWorkflowData.workflow) {
                const dataStr = JSON.stringify(currentWorkflowData.workflow, null, 2);
                const dataBlob = new Blob([dataStr], {type: 'application/json'});
                const url = URL.createObjectURL(dataBlob);
                const link = document.createElement('a');
                link.href = url;
                link.download = 'comfyui_workflow.json';
                document.body.appendChild(link);
                link.click();
                document.body.removeChild(link);
                URL.revokeObjectURL(url);
            }
        }

        async function copyAllData() {
            if (!currentWorkflowData) return;
            
            const allData = `Checkpoint: ${currentWorkflowData.checkpoint || 'Unknown'}
Positive Prompt: ${currentWorkflowData.positivePrompt}
Negative Prompt: ${currentWorkflowData.negativePrompt}
Steps: ${currentWorkflowData.steps || 'Unknown'}
CFG Scale: ${currentWorkflowData.cfgScale || 'Unknown'}
Sampler: ${currentWorkflowData.sampler || 'Unknown'}
Seed: ${currentWorkflowData.seed || 'Unknown'}`;
            
            await copyToClipboard(allData);
        }

        async function parsePNGMetadata(arrayBuffer) {
            const dataView = new DataView(arrayBuffer);
            let offset = 8; // Skip PNG signature
            const metadata = {};

            while (offset < arrayBuffer.byteLength - 8) {
                const length = dataView.getUint32(offset);
                const type = new TextDecoder().decode(arrayBuffer.slice(offset + 4, offset + 8));
                
                if (type === 'tEXt' || type === 'iTXt' || type === 'zTXt') {
                    const chunkData = arrayBuffer.slice(offset + 8, offset + 8 + length);
                    let text;
                    
                    if (type === 'tEXt') {
                        text = new TextDecoder().decode(chunkData);
                    } else if (type === 'iTXt') {
                        // iTXt format: keyword\0compression\0language\0translated_keyword\0text
                        const textData = new TextDecoder().decode(chunkData);
                        const parts = textData.split('\0');
                        if (parts.length >= 5) {
                            metadata[parts[0]] = parts[4];
                        }
                        text = textData;
                    } else if (type === 'zTXt') {
                        // zTXt is compressed - basic parsing (might need proper decompression)
                        text = new TextDecoder().decode(chunkData);
                    }
                    
                    // Parse the text chunk for key-value pairs
                    const nullIndex = text.indexOf('\0');
                    if (nullIndex !== -1) {
                        const key = text.substring(0, nullIndex);
                        const value = text.substring(nullIndex + 1);
                        metadata[key] = value;
                    }
                }
                
                offset += 8 + length + 4; // Move to next chunk (8 = length + type, 4 = CRC)
            }

            return metadata;
        }

        function extractComfyUIData(metadata) {
            // Look for ComfyUI workflow data in various possible fields
            let workflowData = null;
            let promptData = null;

            // Common ComfyUI metadata field names
            const workflowFields = ['workflow', 'Workflow', 'comfy', 'ComfyUI'];
            const promptFields = ['prompt', 'Prompt', 'parameters', 'Parameters'];

            for (const field of workflowFields) {
                if (metadata[field]) {
                    try {
                        workflowData = JSON.parse(metadata[field]);
                        break;
                    } catch (e) {
                        console.log('Failed to parse workflow field:', field);
                    }
                }
            }

            for (const field of promptFields) {
                if (metadata[field]) {
                    try {
                        promptData = JSON.parse(metadata[field]);
                        break;
                    } catch (e) {
                        console.log('Failed to parse prompt field:', field);
                    }
                }
            }

            return { workflow: workflowData, prompt: promptData };
        }

        function updateDataPanel(comfyData, filename) {
            const dataPanel = document.getElementById('data-panel-content');
            if (!dataPanel) return;

            // Extract information from ComfyUI workflow
            let checkpoint = 'Unknown';
            let positivePrompt = 'No prompt found';
            let negativePrompt = 'No negative prompt found';
            let steps = 'Unknown';
            let cfgScale = 'Unknown';
            let sampler = 'Unknown';
            let seed = 'Unknown';

            // Parse prompt data first (more reliable for actual generation parameters)
            if (comfyData.prompt) {
                console.log('Parsing prompt data...');
                const promptNodes = comfyData.prompt;
                
                for (const nodeId in promptNodes) {
                    const node = promptNodes[nodeId];
                    console.log(`Node ${nodeId}:`, node.class_type, node);
                    
                    // Checkpoint
                    if (node.class_type === 'CheckpointLoaderSimple' && node.inputs) {
                        checkpoint = node.inputs.ckpt_name || checkpoint;
                    }
                    
                    // Prompts - need to identify which is positive vs negative
                    if (node.class_type === 'PromptManager' && node.inputs && node.inputs.text) {
                        // PromptManager typically contains the positive prompt
                        positivePrompt = node.inputs.text;
                        console.log('Found PromptManager with text:', positivePrompt.substring(0, 100));
                    }
                    
                    if (node.class_type === 'CLIPTextEncode' && node.inputs && node.inputs.text) {
                        // Check if this looks like a negative prompt
                        const text = node.inputs.text.toLowerCase();
                        if (text.includes('bad anatomy') || text.includes('unfinished') || 
                            text.includes('censored') || text.includes('weird anatomy') ||
                            text.includes('negative') || text.includes('embedding:')) {
                            negativePrompt = node.inputs.text;
                            console.log('Found negative prompt:', negativePrompt.substring(0, 100));
                        } else if (positivePrompt === 'No prompt found') {
                            // If we haven't found a positive prompt yet, this might be it
                            positivePrompt = node.inputs.text;
                            console.log('Found potential positive prompt:', positivePrompt.substring(0, 100));
                        }
                    }
                    
                    // Sampling parameters
                    if (node.class_type === 'KSampler' && node.inputs) {
                        seed = node.inputs.seed || seed;
                        steps = node.inputs.steps || steps;
                        cfgScale = node.inputs.cfg || cfgScale;
                        sampler = node.inputs.sampler_name || sampler;
                    }
                }
            }

            // Fallback to workflow parsing if prompt parsing didn't work well
            if (comfyData.workflow && (positivePrompt === 'No prompt found' || checkpoint === 'Unknown')) {
                console.log('Falling back to workflow parsing...');
                const nodes = comfyData.workflow.nodes || [];
                
                // Look for checkpoint loader
                const checkpointNode = nodes.find(node => 
                    node.type === 'CheckpointLoaderSimple' || 
                    node.type === 'CheckpointLoader'
                );
                if (checkpointNode && checkpointNode.widgets_values) {
                    checkpoint = checkpointNode.widgets_values[0] || checkpoint;
                }

                // Look for prompts in workflow nodes
                const textEncodeNodes = nodes.filter(node => node.type === 'CLIPTextEncode');
                const promptManagerNodes = nodes.filter(node => node.type === 'PromptManager');
                
                // Check PromptManager first for positive prompt
                if (promptManagerNodes.length > 0 && promptManagerNodes[0].widgets_values) {
                    positivePrompt = promptManagerNodes[0].widgets_values[0] || positivePrompt;
                }
                
                // For negative prompt, look for CLIPTextEncode that isn't the positive
                for (const node of textEncodeNodes) {
                    if (node.widgets_values && node.widgets_values[0]) {
                        const text = node.widgets_values[0].toLowerCase();
                        if (text.includes('bad anatomy') || text.includes('unfinished') || 
                            text.includes('censored') || text.includes('weird anatomy')) {
                            negativePrompt = node.widgets_values[0];
                            break;
                        }
                    }
                }

                // Look for sampler
                const samplerNode = nodes.find(node => 
                    node.type === 'KSampler' || 
                    node.type === 'KSamplerAdvanced'
                );
                if (samplerNode && samplerNode.widgets_values) {
                    seed = samplerNode.widgets_values[0] || seed;
                    steps = samplerNode.widgets_values[1] || steps;
                    cfgScale = samplerNode.widgets_values[2] || cfgScale;
                    sampler = samplerNode.widgets_values[3] || sampler;
                }
            }

            // Update the HTML
            dataPanel.innerHTML = `
                <!-- File Path -->
                <div>
                    <h2 class="text-sm font-medium text-gray-300 mb-2">File Path</h2>
                    <div class="text-sm text-blue-400 hover:text-blue-300 cursor-pointer bg-gray-800 p-2 rounded break-all" onclick="openInFileExplorer('${filename}')">
                        ${filename}
                    </div>
                </div>

                <!-- Resources used -->
                <div>
                    <h2 class="text-sm font-medium text-gray-300 mb-2">Resources used</h2>
                    <div class="flex items-center justify-between">
                        <div>
                            <div class="text-blue-400 hover:text-blue-300 cursor-pointer">${checkpoint}</div>
                            <div class="text-xs text-gray-500">ComfyUI Generated</div>
                        </div>
                        <span class="px-2 py-1 text-xs bg-gray-700 text-gray-300 rounded">CHECKPOINT</span>
                    </div>
                </div>

                <!-- Prompt -->
                <div>
                    <div class="flex items-center gap-2 mb-2">
                        <h2 class="text-sm font-medium text-gray-300">Prompt</h2>
                        <span class="px-2 py-1 text-xs bg-orange-600 text-orange-100 rounded">COMFYUI</span>
                        <button class="ml-auto text-gray-400 hover:text-gray-300" onclick="copyPositivePrompt(event)">
                            <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"></path>
                            </svg>
                        </button>
                    </div>
                    <div class="text-sm text-gray-300 bg-gray-800 p-3 rounded max-h-32 overflow-y-auto">
                        ${positivePrompt.substring(0, 200)}${positivePrompt.length > 200 ? '...' : ''}
                    </div>
                    ${positivePrompt.length > 200 ? '<button class="text-blue-400 hover:text-blue-300 text-sm mt-1" onclick="showFullPrompt(\'positive\')">Show more</button>' : ''}
                </div>

                <!-- Negative prompt -->
                <div>
                    <div class="flex items-center justify-between mb-2">
                        <h2 class="text-sm font-medium text-gray-300">Negative prompt</h2>
                        <button class="text-gray-400 hover:text-gray-300" onclick="copyNegativePrompt(event)">
                            <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"></path>
                            </svg>
                        </button>
                    </div>
                    <div class="text-sm text-gray-300 bg-gray-800 p-3 rounded max-h-32 overflow-y-auto">
                        ${negativePrompt.substring(0, 200)}${negativePrompt.length > 200 ? '...' : ''}
                    </div>
                    ${negativePrompt.length > 200 ? '<button class="text-blue-400 hover:text-blue-300 text-sm mt-1" onclick="showFullPrompt(\'negative\')">Show more</button>' : ''}
                </div>

                <!-- Other metadata -->
                <div>
                    <h2 class="text-sm font-medium text-gray-300 mb-3">Other metadata</h2>
                    <div class="flex flex-wrap gap-2">
                        <span class="px-2 py-1 text-xs bg-gray-700 text-gray-300 rounded">CFG SCALE: ${cfgScale}</span>
                        <span class="px-2 py-1 text-xs bg-gray-700 text-gray-300 rounded">STEPS: ${steps}</span>
                        <span class="px-2 py-1 text-xs bg-gray-700 text-gray-300 rounded">SAMPLER: ${sampler}</span>
                    </div>
                    <div class="mt-2">
                        <span class="px-2 py-1 text-xs bg-gray-700 text-gray-300 rounded">SEED: ${seed}</span>
                    </div>
                </div>

                <!-- Raw Workflow Data -->
                <div>
                    <h2 class="text-sm font-medium text-gray-300 mb-2">ComfyUI Workflow</h2>
                    <div class="flex items-center gap-2">
                        <button class="text-blue-400 hover:text-blue-300 text-sm" onclick="showWorkflowData()">View Raw Workflow JSON</button>
                        <button class="text-blue-400 hover:text-blue-300" onclick="downloadWorkflowJSON()" title="Download JSON">
                            <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
                            </svg>
                        </button>
                    </div>
                </div>
            `;

            // Store the full data for later use
            currentWorkflowData = {
                positivePrompt,
                negativePrompt,
                checkpoint,
                steps,
                cfgScale,
                sampler,
                seed,
                workflow: comfyData.workflow,
                prompt: comfyData.prompt
            };
        }

        function showFullPrompt(type) {
            if (currentWorkflowData) {
                const prompt = type === 'positive' ? currentWorkflowData.positivePrompt : currentWorkflowData.negativePrompt;
                const newWindow = window.open('', '_blank');
                newWindow.document.write(`
                    <html>
                        <head><title>${type.charAt(0).toUpperCase() + type.slice(1)} Prompt</title></head>
                        <body style="background: #111; color: #fff; font-family: monospace; padding: 20px;">
                            <h2>${type.charAt(0).toUpperCase() + type.slice(1)} Prompt</h2>
                            <div style="background: #222; padding: 15px; border-radius: 5px; white-space: pre-wrap; line-height: 1.5;">${prompt}</div>
                            <button onclick="navigator.clipboard.writeText(\`${prompt.replace(/`/g, '\\`')}\`).then(() => alert('Copied!'))" style="margin-top: 20px; padding: 10px 20px; background: #444; color: #fff; border: none; border-radius: 5px; cursor: pointer;">Copy to Clipboard</button>
                        </body>
                    </html>
                `);
            }
        }

        function showWorkflowData() {
            if (currentWorkflowData && currentWorkflowData.workflow) {
                const newWindow = window.open('', '_blank');
                newWindow.document.write(`
                    <html>
                        <head><title>ComfyUI Workflow Data</title></head>
                        <body style="background: #111; color: #fff; font-family: monospace; padding: 20px;">
                            <h2>ComfyUI Workflow JSON</h2>
                            <pre style="background: #222; padding: 15px; border-radius: 5px; overflow: auto;">${JSON.stringify(currentWorkflowData.workflow, null, 2)}</pre>
                        </body>
                    </html>
                `);
            }
        }

        async function handleImageUpload(event) {
            const file = event.target.files[0];
            if (!file) return;

            try {
                const arrayBuffer = await file.arrayBuffer();
                const metadata = await parsePNGMetadata(arrayBuffer);
                const comfyData = extractComfyUIData(metadata);
                
                // Update the image display
                const img = document.getElementById('main-image');
                const url = URL.createObjectURL(file);
                img.src = url;
                
                // Update data panel
                updateDataPanel(comfyData, file.name);
                
                console.log('Extracted metadata:', metadata);
                console.log('ComfyUI data:', comfyData);
                
            } catch (error) {
                console.error('Error processing image:', error);
                alert('Error processing image: ' + error.message);
            }
        }

        // Initialize drag and drop
        function initializeDragDrop() {
            const imageArea = document.getElementById('image-area');
            
            imageArea.addEventListener('dragover', (e) => {
                e.preventDefault();
                imageArea.classList.add('bg-gray-900');
            });
            
            imageArea.addEventListener('dragleave', (e) => {
                e.preventDefault();
                imageArea.classList.remove('bg-gray-900');
            });
            
            imageArea.addEventListener('drop', (e) => {
                e.preventDefault();
                imageArea.classList.remove('bg-gray-900');
                
                const files = e.dataTransfer.files;
                if (files.length > 0) {
                    const file = files[0];
                    if (file.type === 'image/png') {
                        const event = { target: { files: [file] } };
                        handleImageUpload(event);
                    } else {
                        alert('Please drop a PNG file');
                    }
                }
            });
        }

        // Initialize when page loads
        window.addEventListener('load', initializeDragDrop);
        
        // Handle window resize to ensure image stays properly sized
        window.addEventListener('resize', () => {
            // The CSS will handle the responsive sizing automatically
            // but we can trigger any additional adjustments if needed
        });
    </script>
</head>
<body class="bg-black text-gray-100 font-sans overflow-hidden">
    <div class="h-screen flex">
        <!-- Main Image Area -->
        <div id="image-area" class="flex-1 flex items-center justify-center p-4 bg-black relative border-2 border-dashed border-transparent transition-colors min-w-0">
            <!-- Upload prompt overlay -->
            <div class="absolute inset-0 flex flex-col items-center justify-center text-gray-500 pointer-events-none">
                <svg class="w-16 h-16 mb-4 opacity-30" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"></path>
                </svg>
                <p class="text-lg mb-2">Drag & Drop PNG with ComfyUI Workflow</p>
                <p class="text-sm">Or click to browse files</p>
            </div>
            
            <!-- File input -->
            <input type="file" id="file-input" accept=".png" class="absolute inset-0 w-full h-full opacity-0 cursor-pointer" onchange="handleImageUpload(event)">
            
            <!-- Navigation arrows -->
            <button class="absolute left-4 top-1/2 transform -translate-y-1/2 w-10 h-10 bg-gray-800 bg-opacity-50 hover:bg-opacity-75 rounded-full flex items-center justify-center text-white transition-all z-10">
                <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"></path>
                </svg>
            </button>
            
            <!-- Main Image -->
            <div class="w-full h-full flex items-center justify-center z-10 pointer-events-none">
                <img id="main-image" 
                     src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='800' height='1200' viewBox='0 0 800 1200'%3E%3Crect width='800' height='1200' fill='%23374151'/%3E%3Ctext x='400' y='600' font-family='Arial' font-size='24' fill='%23D1D5DB' text-anchor='middle'%3EDrop PNG Here%3C/text%3E%3Ctext x='400' y='640' font-family='Arial' font-size='16' fill='%239CA3AF' text-anchor='middle'%3EComfyUI Workflow%3C/text%3E%3C/svg%3E" 
                     alt="Generated Image" 
                     class="max-w-full max-h-full object-contain rounded shadow-2xl">
            </div>
            
            <button class="absolute right-4 top-1/2 transform -translate-y-1/2 w-10 h-10 bg-gray-800 bg-opacity-50 hover:bg-opacity-75 rounded-full flex items-center justify-center text-white transition-all z-10">
                <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path>
                </svg>
            </button>
        </div>

        <!-- Generation Data Panel -->
        <div class="w-96 bg-gray-900 border-l border-gray-700 flex flex-col">
            <!-- Header -->
            <div class="flex items-center justify-between p-4 border-b border-gray-700">
                <div class="flex items-center gap-2">
                    <svg class="w-5 h-5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
                    </svg>
                    <h1 class="text-lg font-medium text-white">Generation data</h1>
                </div>
                <button class="text-xs text-blue-400 hover:text-blue-300 transition-colors" onclick="copyAllData()">
                    📋 COPY ALL
                </button>
            </div>

            <!-- Scrollable Content -->
            <div id="data-panel-content" class="flex-1 overflow-y-auto p-4 space-y-6">
                <!-- Initial placeholder content -->
                <div class="text-center text-gray-500 py-8">
                    <svg class="w-16 h-16 mx-auto mb-4 opacity-30" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
                    </svg>
                    <p class="text-lg mb-2">No Image Loaded</p>
                    <p class="text-sm">Upload a PNG with embedded ComfyUI workflow to view generation data</p>
                </div>
            </div>
        </div>
    </div>
</body>
</html>